package j.quartz.config;

import j.quartz.shiro.auth.RetryLimitHashedCredentialsMatcher;
import j.quartz.shiro.cache.SpringCacheManagerWrapper;
import j.quartz.shiro.realm.JquartzRealm;
import j.quartz.utils.web.SpringContextUtil;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.servlet.Filter;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Shiro 配置
 */
@Configuration
public class ShiroConfigure extends AppCtxConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroConfigure.class);


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        LOGGER.info("===>>> shiroFilterFactoryBean");

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 架构重写Shiro的Filter和自定义的Filter加入到该Map中
        Map<String, Filter> filters = new HashMap<String, Filter>() ;

        Map<String,String> filterChainDefinitionMap = new HashMap<String, String>();

        // 静态资源过滤
        filterChainDefinitionMap.put("/static/**","anon");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login");

        //登出
        filterChainDefinitionMap.put("/logout","logout");

        //错误页面，认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedUrl");
        filterChainDefinitionMap.put("/unauthorizedUrl","port[8080]") ;


        //对所有用户认证
        filterChainDefinitionMap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    /* Realm */
    @Bean
    public JquartzRealm jquartzRealm() {
        JquartzRealm realm = new JquartzRealm() ;
        realm.setAuthenticationCachingEnabled(false);
        realm.setAuthorizationCachingEnabled(false);
        realm.setCredentialsMatcher(
                credentialsMatcher()
        );
        return realm ;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(jquartzRealm());
        return securityManager;
    }

    @Bean
    public RetryLimitHashedCredentialsMatcher credentialsMatcher() {
        RetryLimitHashedCredentialsMatcher credentialsMatcher =
                new RetryLimitHashedCredentialsMatcher(
                        shiroCacheManager()
                );

        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(2);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);

        return credentialsMatcher;
    }

    @Bean
    public SpringCacheManagerWrapper shiroCacheManager() {
        SpringCacheManagerWrapper shiroCacheManager = new SpringCacheManagerWrapper() ;
        EhCacheCacheManager cacheManager = SpringContextUtil.getBean("springCacheManager") ;
        shiroCacheManager.setCacheManager(cacheManager);
        return shiroCacheManager;
    }


    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
        exceptionResolver.setDefaultErrorView("redirect:/404");// 默认错误跳转页面
        exceptionResolver.setExceptionAttribute("ex");// 传递到页面的异常对象，默认为exception
        Properties exceptionMappings = new Properties();
        exceptionMappings.setProperty("org.apache.shiro.authz.UnauthorizedException","redirect:/unauthorizedUrl") ;
        exceptionResolver.setExceptionMappings(exceptionMappings);
        return exceptionResolver ;
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager() ;
//        sessionManager.setSessionDAO(sessionDAO());
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(
                simpleCookie()
        );
        return sessionManager ;
    }

    /**
     * 解决session id 名称冲突问题
     * JSESSIONID
     */
    @Bean
    public SimpleCookie simpleCookie(){
        SimpleCookie simpleCookie = new SimpleCookie() ;
        simpleCookie.setName("SHIRO_SESSION_ID");
        return simpleCookie ;
    }

    /**
     * 覆盖springboot mvc中的 /error 时，需要知名自己的 errorPath
     * 通过改属性 ： ErrorProperties
     * @return
     */
    @Bean
    public ErrorProperties errorProperties(){
        ErrorProperties errorProperties = new ErrorProperties() ;
        errorProperties.setPath("redirect:/404");
        return errorProperties ;
    }


    /*@Bean
    public EhCacheCacheManager ehCacheCacheManager() {
        org.springframework.cache.ehcache.EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
        ehCacheCacheManager.setCacheManager(ehCacheManagerFactoryBean());
        return ehCacheCacheManager ;
    }

    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
        EhCacheManagerFactoryBean factoryBean = new EhCacheManagerFactoryBean();
        factoryBean.setConfigLocation(new ClassPathResource("classpath:props/shiro/ehcache.xml"));
        return factoryBean ;
    }*/


/*
    @Bean
    public IniShiroFilter iniShiroFilter() {
        IniShiroFilter filter = new IniShiroFilter();
        filter.setConfigPath("classpath:shiro.ini");
        return filter ;
    }
*/


}
